import os
import subprocess
import shlex
import platform
import re
import logging
from abc import ABC,abstractmethod
import json
import tarfile

LOGGER = logging.getLogger("Distribute")
FORMAT = '%(asctime)s %(message)s'
logging.basicConfig(format=FORMAT)
LOGGER.setLevel(logging.DEBUG)

def os_name(lists=['Ubuntu',"Manjaro","macos"]):
    plat = platform.platform()
    os = ""
    for cond in lists:
        m = re.findall(r'{}'.format(cond),plat,flags=re.IGNORECASE)
        if len(m)>0:
            os = m[0]
            break
    return os

def extract_compress(filename,dst):
    os.makedirs(dst,exist_ok=True)
    if '.' not in filename:
        raise Exception("{} must be compressed filename and end start with .*".format(filename))
    ext = ".".join(filename.split('.')[1:])
    output = ""
    if filename.endswith('tar.gz'):
        output = os.path.join(dst,os.path.basename(filename).replace('.tar.gz',''))
        if os.path.exists(output):
            LOGGER.debug("{} had exist,skiping ....".format(output))
        else:
            LOGGER.debug("Try to extract {} to {}".format(filename,dst))
            p = subprocess.Popen(shlex.split('tar xzvf {} -C {}'.format(filename,dst)),stdout=subprocess.PIPE)
            mesg = p.stdout.read().decode('uft-8')
    return output

def command_exists(commands):
    output = {}
    for command in commands:
        args = shlex.split("which {}".format(command))
        p = subprocess.Popen(args,stdout=subprocess.PIPE)
        output.update({command:p.stdout.read().decode('utf-8').strip()})
    return output

def install_config(filename):
    with open(filename,'r') as f:
        info = json.load(fp=f)
    return info

class DownloadInstaller(ABC):
    def __init__(self,*arg,**kwargs) -> None:
        pass
    @abstractmethod
    def install(self):
        pass

class DownloadInstallerWithMirror(ABC):
    def __init__(self,*arg,**kwargs) -> None:
        super().__init__(*arg,**kwargs)
    def install(self,**kwargs):
        assert "lists" in kwargs,"lists must be in {}".format(kwargs)
        lists = kwargs['lists']

class DownloadInstallerWithSources(DownloadInstaller):
    def __init__(self,*args,**kwargs) -> None:
        self.config(*args,**kwargs)
        super().__init__(*args,**kwargs)

    def config(self,*args,**kwargs):
        self.shell = self.env()
        if len(kwargs)>0:
            assert 'url' in kwargs,"url must be in {}".format(kwargs.keys())
            assert 'dst' in kwargs,"dst must be in {}".format(kwargs.keys())
            self.install(d)
        elif len(args)>0:
            for d in args:
                self.install(d)
        else:
            logging.raiseExceptions("Input Param {} or {} not right",arg,kwargs)

    def env(self):
        p = subprocess.Popen(shlex.split('which bash'),stdout=subprocess.PIPE)
        shell = p.stdout.read().decode('utf-8').strip()
        if shell is None:
            raise ValueError("Shell is None")
        return shell

    def build(self,config):
        args = [e.strip() for e in '{}/configure && make -j16'.format(config['extract']).split("&&")]
        LOGGER.debug("Command is {}".format(args))
        p = subprocess.Popen(args,stdout=subprocess.PIPE,executable=self.shell,stderr=subprocess.PIPE)
        msg = p.stdout.read().decode('utf-8')
        LOGGER.debug(msg)

    def download(self,config):
        filename = os.path.basename(config['url'])
        dst_filename = os.path.join(config['dst'],filename)
        command = shlex.split("wget -c {} -O {}".format(config['url'],dst_filename))
        if not os.path.exists(dst_filename):
            p = subprocess.Popen(command,stdout=subprocess.PIPE)
            mesg = p.stdout.read().decode('utf-8')
            LOGGER.debug(mesg)
        else:
            LOGGER.debug("{} had been download to {}".format(config['name'],dst_filename))
        return dst_filename

    def install(self,config):
        filename = self.download(config)
        output_path = extract_compress(filename,'/tmp')
        config['extract'] = output_path 
        self.build(config)
        p = subprocess.Popen(shlex.split('sudo make install'),stdout=subprocess.PIPE)
        msg = p.stdout.read().decode('utf-8')
        LOGGER.debug(msg)

if __name__ == "__main__":
    commands = ['nvidia-smi','ls']
    output = command_exists(commands)
    print(output)
    info = install_config('config.json')
    b = DownloadInstallerWithSources(*info)
    
    # b.install()
    
